home *** CD-ROM | disk | FTP | other *** search
/ Languguage OS 2 / Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO / language / parallax / docu_sho < prev    next >
Text File  |  1994-10-29  |  29KB  |  558 lines

  1. Massively Parallel Programming with Parallaxis
  2. ----------------------------------------------
  3.  
  4. Thomas Braunl
  5.  
  6. Universitaet Stuttgart, IPVR
  7. Breitwiesenstr. 20-22, D-7000 Stuttgart 80, FRG
  8.  
  9. e-mail: braunl@informatik.uni-stuttgart.de
  10.  
  11. ### This paper only partially covers version 1 of the Parallaxis system,
  12. ### no version 2 extensions are being discussed!
  13.  
  14. Abstract
  15.  
  16. In the Parallaxis programming language, the model of a parallel architecture 
  17. is included as an integral part of the problem solution. That is, the 
  18. combination of algorithm and machine model accounts for an entire 
  19. specification. Since the choice of the computer architecture largely determines
  20. the structure of the algorithm applied, a structured parallel programming 
  21. language should be given the expressive power of stating, or even better, 
  22. selecting the structure of the parallel architecture, for which an algorithm 
  23. is bound. Our language model Parallaxis operates on the class of SIMD array 
  24. processors. In addition to the concurrent algorithm, Parallaxis allows the 
  25. specification of arbitrary network topologies by means of a functional 
  26. description with configuration and connection specifications. Simple concepts 
  27. for concurrent execution of statements and message passing are based on these 
  28. definitions. Variable declaration takes the parallel machine model into account
  29. and therefore splits into variables for the control unit (scalars) and 
  30. variables for each of the parallel processing units (vectors).
  31.  
  32.  
  33. 1. Introduction
  34.  
  35. The Parallaxis language model was designed to allow structured parallel programming in a high 
  36. level language, similar to sequential Pascal or Modula-2. The compiler should be ma-
  37. chine-independent, so it can be used for a wide range of parallel architectures. In addition, it 
  38. should be useful in exploiting the parallel resources of any particular architecture satisfying the 
  39. basic machine model, in order to achieve optimal performance. Both goals (which might look 
  40. contradictory, at first) are achieved by a translation into a low level intermediate parallel lan-
  41. guage which is  processed by a machine-dependent interpreter or compiler. This flexible model 
  42. is restricted to SIMD structures; it combines the internal representation of the hardware struc-
  43. ture with the topology- or structure-specific algorithm to form a complete problem solution. 
  44. Thus, it is possible to specify number and arrangement of processing elements, as well as their 
  45. communication network in Parallaxis.
  46.  
  47. Here, we get a new meaning of the term structured. The whole problem solution is structured, 
  48. including the algorithm, as well as the architecture for which the algorithm is bound. Given this 
  49. semantics, it is necessary to include a machine description, if the language should not be re-
  50. stricted to a single architecture that is implicitly assumed. An algorithm for the same problem 
  51. will look totally different if designed for a hypercube instead of a ring-topology. Besides, for a 
  52. certain problem there may be structures well suited and others that do not match very well. If 
  53. there is a choice (as for reconfigurable parallel systems), the architecture specification can be 
  54. used for creating the best matching architecture.
  55.  
  56. In this paper, I will address the language concepts supporting the Parallaxis user in pro-
  57. gramming a SIMD computer on a high level of abstraction. I will not be concerned at this 
  58. point, however, what strategy or algorithm to apply in order to perform an efficient mapping 
  59. between a topology specified for a certain application and the topology provided by the physi-
  60. cal hardware structure. This problem is handled automatically on a lower operating system 
  61. level, transparent to the user. However, it will greatly affect the efficiency of an application 
  62. with heavy communication. H. J. Siegel developed efficient mapping algorithms for simulating 
  63. one topology on a different topology.
  64.  
  65. Corresponding to the machine model of a processor-network, controlled by a single control 
  66. unit, variables may be declared either for the control unit (using the declaration keyword 
  67. scalar), or for each of the PEs (using vector). Each variable is strictly typed, like in Modula-2, 
  68. so there may be no vector variables in an expression that is to be assigned to a scalar variable. 
  69. Vectors may be used inside explicitly marked parallel blocks or operations only while scalars 
  70. may also appear in parallel vector expressions (requiring a duplication or broadcast of that par-
  71. ticular value).
  72.  
  73.  
  74. 2.  Specification of Network Topologies
  75.  
  76. Parallaxis makes the following assumptions about its abstract parallel machine, whether it is 
  77. physically present or simulated:
  78.  
  79. *    SIMD structure with
  80.    -    central control unit
  81.    -    variable number of processing elements (PEs)
  82.    -    flexible (reroutable) communication network  that is,
  83.     it can be used as if forming any topological structure
  84. *    all operations occur synchronously
  85. *    all PEs are identical in processor and memory structure
  86. *    each PE owns the same number of bi-directional ports
  87.     for sending and receiving messages
  88. *    one process per PE
  89.  
  90.                               
  91. Within the realm of this machine model, the programmer may now choose a certain topological 
  92. structure for the communication network to achieve the best possible match between ar-
  93. chitecture and algorithm of a given problem. For each application, the number of PEs and the 
  94. network topology is static, that is, it has to be specified prior to compilation and will remain 
  95. unchanged during program execution.
  96.  
  97. The specification of the network structure's logical form takes two steps: First, Parallaxis is 
  98. told the number of processing elements one wants to use and how they will be arranged in di-
  99. mensions. This almost exactly takes the form of Modula-2's array declaration, except that we 
  100. are dealing with processors here instead of data elements. Although we create some neighbor 
  101. relation between the PEs by this declaration, this does not specify any connections between 
  102. processors which is reserved for the second step. There, we may specify a transfer-function 
  103. (from a general PE position to its relative neighbor) for every processor-port in this topology. 
  104. Or, stated differently, the number of transfer-functions provided equals the number of ports per 
  105. PE. Each transfer-function has a name (the exit-port's name) and also states the name of the 
  106. corresponding entry port on its neighbor-PE after a period.
  107.  
  108. Parallaxis allows the specification of arbitrary network topologies. The examples shown in the 
  109. following sections should be guidelines for modeling other topologies.
  110.  
  111.  
  112. 2.1  Ring Structure
  113.  
  114. The simple topological structure of a ring may be specified as follows in Parallaxis:
  115.  
  116.                                
  117. CONFIGURATION  ring [12];
  118. CONNECTION  c_wise : ring[i]  ->  ring[(i+1) mod 12].cc_wise; 
  119.             cc_wise: ring[i]  ->  ring[(i-1) mod 12].c_wise;
  120.  
  121.           11  ---  0  ---  1
  122.            |               |
  123.           10               2
  124.            |               |
  125.            9               3             <-- PE -->
  126.            |               |          cc_wise   c_wise
  127.            8               4
  128.            |               |
  129.            7  ---  6  ---  5
  130.  
  131. Figure 1:  ring topology
  132.  
  133. With the configuration specification the user tells the system to reserve twelve processors, la-
  134. beled zero to eleven, that are arranged in a single dimension. Each PE owns two ports, called 
  135. c_wise (for clockwise mapping) and cc_wise (for counter-clockwise mapping), corresponding 
  136. to these two transfer-functions. While the function c_wise maps any processing element to the 
  137. next higher PE, the function cc_wise maps any element to the next lower one. Using the mod-
  138. ulo-operator results in a closed topology that is, every element has a neighbor at every port.
  139.  
  140.  
  141. 2.2  Two-Dimensional Grids
  142.  
  143. Now, let us take a look at some simple two-dimensional network structures: the grid, an open 
  144. topology that might be useful in application areas ranging from image processing to air flow 
  145. analysis for wing profile design, and its closed counterpart the torus (see figure 2).
  146.  
  147.                                                    ^    ^    ^    ^    ^
  148.                                                    |    |    |    |    |
  149. grid   X -- X -- X -- X -- X         torus      <- X -- X -- X -- X -- X ->
  150.        |    |    |    |    |         (wrapped      |    |    |    |    |
  151.        X -- X -- X -- X -- X          around)   <- X -- X -- X -- X -- X ->
  152.        |    |    |    |    |                       |    |    |    |    |
  153.        X -- X -- X -- X -- X                    <- X -- X -- X -- X -- X ->
  154.        |    |    |    |    |                       |    |    |    |    |
  155.        X -- X -- X -- X -- X                    <- X -- X -- X -- X -- X ->
  156.                                                    |    |    |    |    |
  157.                                                    v    v    v    v    v
  158.  
  159. Figure 2:  two-dimensional grid and torus
  160.  
  161. Their specification in Parallaxis is straightforward, as shown in figure 3. It takes just four 
  162. transfer-functions to specify the whole grid with each PE owning four data-ports (here called: 
  163. north, south, east, and west). The torus specification is almost identical; the additional modulo-
  164. operator connects opposite boundary-PEs. When considering the grid specification, there are 
  165. PEs whose neighbor function evaluates to an invalid PE-number: e.g. the PE at position [2,4] 
  166. would have a right neighbor [2,5], but this is out of bounds as of the grid size fixed in the 
  167. CONNECTION specification (rows labeled 0 to 3, and columns labeled 0 to 4). By definition, 
  168. these PEs (called "boundary-PEs") simply do not have a connection in that particular direction. 
  169. Any data exchange to or from the outside will have no effect (see section 4 for more detail).
  170.  
  171.     CONFIGURATION grid [4] [5];
  172.     CONNECTION    north: grid[i,j]    ->  grid[i+1, j].south;
  173.                   south: grid[i,j]    ->  grid[i-1, j].north;
  174.                   east : grid[i,j]    ->  grid[i, j+1].west;
  175.                   west : grid[i,j]    ->  grid[i, j-1].east;
  176.     
  177.     CONFIGURATION torus [4] [5];
  178.     CONNECTION    north: torus[i,j]     ->  torus[(i+1) mod 4, j].south;
  179.                   south: torus[i,j]     ->  torus[(i-1) mod 4, j].north;
  180.                   east : torus[i,j]     ->  torus[i, (j+1) mod 5].west;
  181.                   west : torus[i,j]     ->  torus[i, (j-1) mod 5].east;
  182.     
  183. Figure 3:  grid and torus specification
  184.  
  185.  
  186. 3.  Variable Declaration
  187.  
  188. As seen before, we have to deal with a basically two-fold system structure:
  189.  
  190. *    a controlling host  and
  191. *    a network of processing elements.
  192.  
  193. Variables that are used for controlling the execution sequence, such as a counting variable in a 
  194. for-loop,  should exist only once at the host computer while a variable used for vector compu-
  195. tations might be required once for each PE. To distinguish these two types of variable declara-
  196. tions, Parallaxis offers the phrases scalar for declaring a variable at the host, and vector for 
  197. declaring a variable to appear in every PE's memory structure, thus overall creating a vector (or 
  198. some higher order data structure, like a matrix, etc., depending on the specified network topo-
  199. logy). An example follows:
  200.  
  201.   SCALAR  i,j: integer;
  202.   VECTOR  a,b: real;
  203.           c,d: integer;
  204.  
  205. The distinction between scalar and vector variables is also necessary for formal procedure pa-
  206. rameters and local variable declarations.
  207.  
  208.  
  209. 4.  Parallel Programming Concepts
  210.  
  211. Parallaxis provides language primitives to account for the parallel machine model which build 
  212. on the topological structure specified by means of configuration and connection. There are 
  213. three basic concepts for parallel processing in Parallaxis:
  214.  
  215.     1.     parallel execution     ("parallel block")
  216.     2.    parallel data exchange    ("propagate operation")
  217.     3.    vector reduction    ("reduce function")
  218.  
  219.  
  220. 4.1  Parallel Execution
  221.  
  222. In analogy to the begin-end block used to group statements to be executed sequentially, there is 
  223. the parallel-endparallel block for synchronous parallel statements. The semantics hereby is that 
  224. every processing element executes the same statement with its own local values of the variables 
  225. involved, thus obtaining individual results. So the phrase parallel mustn't lead to an erroneous 
  226. interpretation: all statements contained in this block are executed sequentially under central 
  227. control, but they are performed data-parallel. Together with a unique control flow this just re-
  228. flects the single instructionJP multiple data (SIMD) machine model.
  229.  
  230. Because of the SIMD restriction, each PE may execute the current instruction or remain idle; a 
  231. concurrent execution of different instructions is not possible. There are two ways of selecting 
  232. PEs for parallel execution in Parallaxis which may also be combined:
  233.  
  234.     A)    by explicitly stating their network position at the entrance of a parallel block
  235.         for each dimension specified
  236.         e.g., for a one-dimensional structure:
  237.  
  238.         PARALLEL [22..44]
  239.           <parallel statements>
  240.         ENDPARALLEL
  241.  
  242.     B)    by using if-, case-selections or while-, repeat-loops with vector conditions
  243.         e.g.:
  244.  
  245.         PARALLEL
  246.           IF <vector expression> THEN <parallel statements> END
  247.         ENDPARALLEL
  248.  
  249. In case A, only the PEs within the selected range execute the statements inside the parallel 
  250. block, all others remain idle during that time. PE selections may be constant or variable posi-
  251. tional expressions, such as subrange, enumeration, and set. One selection is required for every 
  252. dimension.
  253.  
  254. In case B, a conditional expression determines which PEs will execute the statements of the 
  255. then-branch and which will remain idle. While the branching-condition evaluates to true for one 
  256. processor, it might be false for others. The condition is evaluated for each PE individually in 
  257. parallel and only those PEs for which the condition evaluates to true will execute the then-
  258. branch; all other PEs remain idle. If there exists an else-branch, it will be executed subse-
  259. quently with the inverse PE group. The two branches of an if-selection cannot be executed in 
  260. parallel because of the previously mentioned "single control flow" SIMD restriction. Therefore, 
  261. they have to be serialized. Processors that execute the then-part may continue while processors 
  262. executing the else-part are blocked with their identifications pushed onto a global stack at the 
  263. controlling host. They remain inactive while the host supervises execution of the then-part. 
  264. Afterwards, when executing the else-part, the processor sets change places, that is, the "then-
  265. processors" now become inactive for some time while the "else-processors" are active. The use 
  266. of a dynamic stack also accounts for nested if-statements. Each stack-entry corresponds to a 
  267. nesting-level of if-statements. Since serialization degrades the performance of a parallel system, 
  268. the user should keep this fact in mind when designing a parallel algorithm.
  269.  
  270. The semantics of a parallel loop is analogous: only those PEs satisfying the loop-condition 
  271. execute the loop-statements. A loop can only be terminated when none of the active PEs satis-
  272. fy the loop-condition. As long as a single PE remains, the loop is being continued while all 
  273. PEs excluded by the loop-condition are idle. This means, the controlling host has to get a feed-
  274. back from the network whether there are PEs remaining or not. The implementation of this 
  275. feedback depends on the hardware facilities of the target system. In any case, the OR-reduction 
  276. of the condition-vector (see also section 4.3) returns this information to the host.
  277.  
  278.  
  279. 4.2  Parallel Data Exchange
  280.  
  281. The propagate-operation accounts for data exchange between the parallel processors. Propagate 
  282. behaves like a compound statement of send followed immediately by receive. All selected (or 
  283. active) PEs participate in this parallel data exchange. In its simple form, the propagate-opera-
  284. tion reads:
  285.     propagate.<direction> ( <vector variable> )
  286.     e.g., for the ring structure of section 2.1:
  287.     propagate.c_wise (x)
  288.  
  289. The semantics of this statement is that the value of a vector (here: "x") is propagated through 
  290. the network by one step in the stated direction (here: "c_wise" for clockwise). The direction 
  291. names directly refer to the CONNECTION specification of the network where they were defined 
  292. as exit-ports. For simple network structures like ring, grid, hypercube, and so on, the corre-
  293. sponding entry-port is unambiguous. Therefore, it can be determined automatically by Par-
  294. allaxis (in our ring example: "cc_wise"). For complex topologies (as the tree structure, see 
  295. section 6) both send-port and receive-port have to be supplied, in order to perform the propa-
  296. gate-operation.
  297.  
  298. Let us now assume that the PEs labeled 3 to 8 of the twelve ring PEs have been selected 
  299. (activated) to perform the above propagate-operation. Each PE sends a message (here: the local 
  300. value of variable "x") to its clockwise neighbor and then reads a message from its counter-
  301. clockwise neighbor, since the port cc_wise was defined to be the entry for c_wise in the con-
  302. nection specification. Disregarding those basic sends and receives, we recognize that informa-
  303. tion has been propagated one shift in clockwise direction all around the selected sector, thus 
  304. reflecting the operation's name. Though the ring represents a closed topology, the sector se-
  305. lected here is equivalent to an open topology. Interesting is the behavior at the boundary, which 
  306. in our example are PEs no. 3 and 8. PE no. 3 does not have an active neighbor 
  307. for receiving (direction "cc_wise") while PE no. 8 does not have a neighbor for sending 
  308. (direction "c_wise"). As of the propagate-operation, this is equivalent to not having a neighbor 
  309. at all for that direction in an open topology. PE no. 3 first sends its message along to PE no. 4. 
  310. Since it cannot perform a subsequent receive, its local value of "x" remains unchanged. PE 
  311. no. 8 's send goes without any effect (its neighbor is inactive) while the receive operation 
  312. can be performed normally.
  313.  
  314.                               
  315. Other syntactical form of the propagate-operation allow:
  316.  
  317. *    the separation between send-expression and receive-variable
  318.     (in case one does not want to overwrite the variable as in the previous
  319.     form)
  320.     e.g.:    propagate.c_wise (x+1,y)
  321.  
  322. *    the propagation of several steps along a fixed direction
  323.     e.g.:    propagate.c_wise ^5 (x)
  324.  
  325.  
  326. 4.3  Vector Reduction
  327.  
  328. Sometimes not the whole vector is of interest, but only a scalar reduction of it like its sum. 
  329. Without a specialized operation, this scalar information is awkward to get. Parallaxis provides 
  330. load and download operations to move a scalar array at the host to and from a vector distributed 
  331. over the network. So, in order to get the sum of a vector, one has to download the complete 
  332. vector to the host and then add it up iteratively. The reduce-function enables a vector reduction 
  333. in a single statement and without involving additional variables. The desired reduction opera-
  334. tion has to be specified after a period. Predefined are sum, product, and, or, min, max, first, 
  335. and last; user defined functions with appropriate parameters may be used as well.
  336.  
  337. The reduce-operation is completely independent of the specified topology; it is a primitive, one-
  338. dimensional vector operation. Specialized components of a parallel system may execute this 
  339. command in time O(log2 n) in a tree-like operation mode.
  340.  
  341. Assume "s" being a real scalar and "x" being a real vector:
  342.     s := REDUCE.sum (x)
  343. This statement assigns the component-wise sum of vector "x" to scalar "s".
  344.  
  345.  
  346. 5.  Sample Programs
  347.  
  348. Now, we are going to look at a couple of Parallaxis programs. The first shows 
  349. a parallel sorting algorithm, called "odd-even transposition sorting",
  350. the second is a parallel version of the "Sieve of Eratosthenes" for
  351. generating prime numbers.
  352.  
  353. "Odd-Even Transposition Sorting" (OETS) is a parallel sorting algorithm that is able to sort n 
  354. numbers on n PEs in time O(n). The PEs are connected in a bi-directional, open linear list;  I/O 
  355. instructions have been omitted for clarity. In odd iteration steps, the PE-pairs 1-2, 3-4, and so 
  356. on are compared in parallel while in even iteration steps the pairs 2-3, 4-5, and so on are han-
  357. dled.
  358.  
  359.     SYSTEM sorting;
  360.     CONST  n = 1000;
  361.     CONFIGURATION list [1..n];
  362.     CONNECTION   left : list[i]  ->  list[i-1].right;
  363.                     right: list[i]  ->  list[i+1].left;
  364.  
  365.     SCALAR  k       : integer;
  366.     VECTOR  val,r,l : integer;
  367.                swap    : boolean;
  368.  
  369.     BEGIN
  370.       ... (* read input data *)
  371.       FOR k:=1 TO n DO
  372.         PARALLEL
  373.           PROPAGATE.right(val,l);
  374.           PROPAGATE.left (val,r);
  375.           (* l/r now hold the left/right neighbors' values *)
  376.           swap := false;
  377.  
  378.           IF odd(k) THEN  (* compare 1-2, 3-4, ... *)
  379.             IF odd(dim1) AND (r < val) THEN
  380.               val  := r;
  381.               swap := true
  382.             END
  383.           ELSE  (* even (k)  compare 2-3, 4-5, ... *)
  384.             IF even(dim1) AND (r < val) THEN
  385.               val  := r;
  386.               swap := true
  387.             END;
  388.           END;
  389.  
  390.           PROPAGATE.right(swap);
  391.           IF swap AND (id_no>1) THEN val := l END;
  392.         ENDPARALLEL
  393.       END;
  394.       ... (* write output data *)
  395.     END sorting.
  396.  
  397.  
  398. Each PE holds one component of the vector "val" that is to be sorted, as well 
  399. as local copies of each one's left and right neighbor. The marker variable 
  400. "swap" is used for the bookkeeping of swap operations to be finished at the 
  401. right neighbor PEs. A different approach without marker propagation is 
  402. possible, but complicates the program.
  403.  
  404.  
  405. The program for generating prime numbers is very much straight-forward and
  406. does not need a lot of explanation. In each iteration through the "while"-
  407. loop, all multiples of the current number are eliminated in parallel. Execution
  408. of the loop continues until no "candidate" (on any PE) is left.
  409.  
  410.  
  411.     SYSTEM sieve;
  412.     CONFIGURATION list [1000];
  413.     CONNECTION (* none *);
  414.  
  415.     SCALAR prime: integer;
  416.     VECTOR candidate: boolean;
  417.  
  418.     BEGIN
  419.       PARALLEL
  420.         candidate := id_no >=2;
  421.         WHILE candidate DO
  422.           prime:= REDUCE.First(id_no);
  423.           WriteInt(prime,10); WriteLn;
  424.           IF id_no MOD prime = 0 THEN candidate:=FALSE END
  425.         END
  426.       ENDPARALLEL
  427.     END sieve.
  428.  
  429.  
  430. 6.  Parallaxis Syntax
  431.  
  432. Parallaxis Language Definition
  433. (c) Thomas Braunl, Universitaet Stuttgart, 1989
  434.  
  435. System          =       SYSTEM  sys_ident ";"
  436.                         { ConstantDecl  |  TypeDecl }
  437.                         HardwareDecl  SoftwareDecl 
  438.                         sys_ident "." .
  439.  
  440. ConstantDecl    =       CONST  { ident "=" ConstExpr ";" } .
  441. TypeDecl        =       TYPE  { ident "=" type ";" } .
  442.  
  443. HardwareDecl    =       CONFIGURATION  conf_ident  IntRange  { "," IntRange }  ";" 
  444.                         CONNECTION  [ TransferFunc  { ";"  TransferFunc } ] ";" .
  445. IntRange        =       "["  range  "]" .
  446. range           =       int_ConstExpr  [ ".." int_ConstExpr ] .
  447. TransferFunc    =       out_direction  ":" conf_ident
  448.                         "[" source   { "," source } "]"  ( "->" | "<->" )
  449.                         destination  { "," destination } .
  450. direction       =       ident  [ "(" (integer | const_ident) ")" ] .
  451. source          =       ident  |  integer.
  452. destination     =       [ discriminant ]
  453.                         conf_ident  "["  ExprList  "]"  "."  in_direction.
  454. discriminant    =       "{"  bool_expr  "}".
  455.  
  456. SoftwareDecl    =       VariableDecl  { ProcedureDecl ";" }
  457.                         block .
  458. VariableDecl    =       [ ControlVarDecl ]  [ LocalVarDecl ] .
  459. ControlVarDecl  =       SCALAR { ident { "," ident } ":" type ";" } .
  460. LocalVarDecl    =       VECTOR { ident { "," ident } ":" type ";" } .
  461. ProcedureDecl   =       PROCEDURE proc_ident [FormalParams] ";"
  462.                         { ConstantDecl  |  TypeDecl }
  463.                         SoftwareDecl proc_ident .
  464. FormalParams    =       "(" [ parameters  { ";" parameters } ] ")"
  465.                         [ ":" ( SCALAR  |  VECTOR )  function_type ] .
  466. parameters      =       SCALAR  [ VAR ]  ident  { "," ident } ":" type  |
  467.                         VECTOR  [ VAR ]  ident  { "," ident  } ":" type .
  468.  
  469. block           =       BEGIN
  470.                         StatementSeq
  471.                         END .
  472. StatementSeq    =       statement  { ";" statement } .
  473. statement       =       [  assignment  |  ProcedureCall  | 
  474.                           IfSelection  |  CaseSelection  |  WhileLoop  |
  475.                           RepeatLoop   |   LoopStatement |  ForLoop    |
  476.                           WithStatement |  EXIT   |  RETURN  [ expr ]  |
  477.                           ParallelExec  |  Propagate |  Load  |  Store  ] .
  478.  
  479. ParallelExec    =       PARALLEL  selection
  480.                         StatementSeq
  481.                         ENDPARALLEL .
  482. selection       =       [  "[" entry  "]"  { "," "[" entry  "]" }  ] .
  483. entry           =       range  { "," range }  |  expr  [ ".." expr ]  | "*" .
  484.  
  485. Propagate       =       PROPAGATE "." out_dirvar  [ "^"  ( integer | ident) ]
  486.                                          [      "." in_dirvar ]
  487.                           "("  vector_designator  [ "," vector_designator ]  ")" .
  488. dirvar          =       ident [ "(" expr ")" ] .
  489. Load            =       LOAD  selection  "(" vector_designator "," scalar_designator
  490.                                 [ "," length_designator ] ")" .
  491. Store           =       STORE  selection  "(" vector_designator "," scalar_designator
  492.                                 [ "," length_designator ] ")" .
  493. Reduce          =       REDUCE  "."  operator_ident  selection  "(" expr ")" .
  494.  
  495. assignment      =       designator  ":="  expr .
  496. designator      =       ident { "[" ExprList "]"  |  "." ident } .
  497. ProcedureCall   =       proc_ident [ "("  ExprList  ")" ] .
  498. FunctionCall    =       proc_ident   "("  [ ExprList ]  ")" .
  499. IfSelection     =       IF bool_expr THEN StatementSeq
  500.                         { ELSIF bool_expr THEN StatementSeq }
  501.                         [ ELSE StatementSeq ] END .
  502. CaseSelection   =       CASE  expr  OF  case { "|" case }
  503.                         [ ELSE  StatementSeq ]  END.
  504. case            =       CaseLabels  { "," CaseLabels }  ":"  StatementSeq .
  505. CaseLabels      =       ConstExpr [ ".." ConstExpr ] .
  506. WhileLoop       =       WHILE  bool_expr  DO  StatementSeq  END .
  507. RepeatLoop      =       REPEAT  StatementSeq  UNTIL  bool_expr .
  508. LoopStatement   =       LOOP  StatementSeq  END .
  509. ForLoop         =       FOR ident  ":="  expr  TO expr  [ BY ConstExpr ] 
  510.                         DO StatementSeq END .
  511. WithStatement   =       WITH  designator  DO  StatementSeq  END .
  512.  
  513. type            =       SimpleType | ArrayType| RecordType | SetType .
  514. SimpleType      =       type_ident |  enumeration  |  subrange .
  515. enumeration     =       "(" const_ident  { "," const_ident } ")" .
  516. subrange        =       "["  ConstExpr  ".."  ConstExpr  "]" .
  517. ArrayType       =       ARRAY SimpleType { "," SimpleType } OF type .
  518. RecordType      =       RECORD FieldListSeq END .
  519. FieldListSeq    =       FieldList  { ";"  FieldList } .
  520. FieldList       =       [ ident { "," ident } ":" type ] .
  521.                         (* variant records not yet supported *)
  522. SetType         =       SET OF SimpleType .
  523.  
  524. ExprList        =       expr  { "," expr } .
  525. expr            =       SimpleExpr   { relation SimpleExpr } .
  526. relation        =       "=" | "<>" | "#" | "<" | ">" | "<=" | ">=" | IN .
  527. SimpleExpr      =       [ "+" | "-" ]  term  { AddOperator term } .
  528. AddOperator     =       "+" | "-" | OR .
  529. term            =       power  { MulOperator power} .
  530. MulOperator     =       "*" | "/" | DIV | MOD | AND | "&" .
  531. power           =       factor  { "^"  factor } .
  532. factor          =       FunctionCall  |  Reduce  |  string  |  set  |
  533.                         number  |  designator  |  structure  |
  534.                         "(" expr ")"  |  NOT  factor .
  535. string          =       "'" { character } "'"  |  '"' { character } '"' .
  536. set             =       [type_ident] "{" [ element  { "," element } ] "}" .
  537. element         =       ConstExpr [ ".." ConstExpr ] .
  538. structure       =       record_ident  "("  ExprList  ")" .
  539.  
  540. CExprList       =       [ ConstExpr  { ","  ConstExpr } ] .
  541. ConstExpr       =       SimpleConstExpr  { relation  SimpleConstExpr } .
  542. SimpleConstExpr =       [ "+" | "-" ]  ConstTerm  { AddOperator  ConstTerm } .
  543. ConstTerm       =       ConstPower  { MulOperator  ConstPower } .
  544. ConstPower      =       ConstFactor  { "^"  ConstFactor } .
  545. ConstFactor     =       const_ident  |  number  |  string  |  set  |
  546.                         recarr_ident "(" CExprList ")"  |
  547.                         stdfct_ident "(" CExprList ")"  |
  548.                         "(" ConstExpr ")"  |  NOT  ConstFactor .
  549.  
  550. number          =       integer  | real .
  551. integer         =       digit {digit} .
  552. real            =       digit {digit} "." {digit} ["E" ["+" | "-"] digit {digit}] .
  553. ident           =       letter { letter | digit } .
  554. character       =       letter | digit | "$" | .. (* any character, e.g. ASCII *) .
  555. digit           =       "0" | . . | "9" .
  556. letter          =       "A" | . . | "Z" | "a" | . . | "z" | "_" .
  557.  
  558.